-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace checkers with validators #36
Conversation
Wow. Not really available for review today, but I took a quick glance and it looks very professional as usual. I'll take the time to review asap! |
No rush. I haven't yet tried it with any of our projects :) |
README.rst
Outdated
raise ValueError('%s must be a a string or a compiled regex ' | ||
'(use re.compile)' % name) | ||
# Raise ValidationError | ||
raise ValidationError('%s must be a string or a compiled regex (use re.compile)') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, will Django populate the %s
itself? I think it should be like what you wrote later:
raise ValidationError('%(value)s is not a string or a compiled regex (use re.compile)',
params={'value': value})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, moreover it's recommended way to raise a ValidationError
, see https://docs.djangoproject.com/en/2.1/ref/forms/validation/#raising-validationerror
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you simply copy-paste it then 🙂 ? So both examples use the recommended way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I get the problem. Thanks :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great PR, thanks 🙂 Just a few questions/changes before merging, but nothing crazy.
docs/usage.rst
Outdated
|
||
The second way is to subclass ``appsettings.Setting`` and write a custom | ||
``checker`` method: | ||
The most customization can be reached by customizing the ``validate()`` method. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The most customization
sounds wrong, maybe something like The finest-grained customization can be obtained
would be better? Or maybe you forgot a word?
More complex customization can be reached
?
src/appsettings/settings.py
Outdated
self.validators.append(ValuesTypeValidator(item_type)) | ||
if empty is not None: | ||
warnings.warn("Empty argument is deprecated, use min_length instead.", DeprecationWarning) | ||
min_length = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we check if empty is true or false? Deprecation is a thing, but the behavior should stay the same. If the user says empty is allowed (true), then min length should be 0 (or None, to avoid adding an unnecessary validator). If not (false), then indeed min length should be 1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, looks like I got ahead of myself.
src/appsettings/settings.py
Outdated
call_default=call_default, transform_default=transform_default, validators=validators) | ||
if empty is not None: | ||
warnings.warn("Empty argument is deprecated, use min_length instead.", DeprecationWarning) | ||
min_length = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as for IterableSetting.
src/appsettings/settings.py
Outdated
**checker_kwargs): | ||
default_validators = (TypeValidator(list), ) | ||
|
||
def __init__(self, name='', default=list, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In previous classes you didn't use **kwargs
, is there a reason? I like using **kwargs
because avoids duplicated code, however it can decrease the ability of introspection (IDE popup with method's accepted arguments is my main example). So I'm not sure 😄 What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed, most of them now override the __init__
just to provide a different default value. I was hoping to solve that in subsequent PR. I've created #37, so I don't forget.
I have tried to use the **kwargs
whenever possible as the number of arguments is quite large, and in this case I consider the duplication worse than missing introspection. In places where it's not used, new argument are appended.
Also I forgot about *args
, so I wiil add them as well, in case somebody uses them.
src/appsettings/settings.py
Outdated
self.validators.append(DictValuesTypeValidator(value_type)) | ||
if empty is not None: | ||
warnings.warn("Empty argument is deprecated, use min_length instead.", DeprecationWarning) | ||
min_length = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as for IterableSetting and StringSetting.
src/appsettings/settings.py
Outdated
empty (bool): whether empty iterable is allowed. Deprecated in favor of min_length. | ||
""" | ||
if key_type is not None: | ||
warnings.warn("Argument key_type does nothing and is deprecated.", DeprecationWarning) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should it be deprecated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't found any use case nor restriction to maintain it. Objects which can serve as a key in dictionary are limited to hashables by python and I don't actually see any benefits in further restriction.
I'm not very strong about this, so if you have any arguments to keep it, I'm open to reconsider.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One could want to restrict the key type to int
only:
# official django setting
MESSAGE_TAGS = {
messages.DEBUG: 'default',
messages.INFO: 'info',
messages.SUCCESS: 'success',
messages.WARNING: 'warning',
messages.ERROR: 'danger',
}
Or any other hashable type, like a tuple.
NEURONAL_NETWORK = {
(0, 0, 0): 1,
(0, 0, 1): 0,
...
}
Since I'm going to manipulate the keys as well, I like the possibility to enforce their type so I don't have to do it manually.
Even if I never use the key_type, I just like to know that I can. Afterall we already have a DictValuesTypeValidator, so why not a DictKeysTypeValidator as well? It's only 14 lines of code 😛
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, The integers make a good point.
src/appsettings/settings.py
Outdated
validators (list of callables): list of additional validators to use. | ||
min_length (int): minimum length of the iterable (included). | ||
max_length (int): maximum length of the iterable (included). | ||
empty (bool): whether empty iterable is allowed. Deprecated in favor of min_length. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do min_length and max_length make sense for the ObjectSetting? Maybe we should instead warn if they are present and pop them from the kwargs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, I don't see any point. That also applies to empty
argument.
src/appsettings/settings.py
Outdated
subsetting.check() | ||
super(NestedSetting, self).check() | ||
for subsetting in self.settings.values(): | ||
subsetting.check() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same remark as above, should we store exception messages and concatenate them before reraising?
5270586
to
d33b57c
Compare
Round 1: fixed and rebased. |
Great thanks 🙂 Just three things left: simple copy-paste for the regex validation example in readme, your thoughts about a DictKeysTypeValidator, and warning + dict pop for min_length max_length and empty for the ObjectSetting. |
I have noticed the |
d33b57c
to
3e4c691
Compare
Round 2: fixed and rebased. Only the new comment about |
So, do you want to remove the min_length max_length and empty args for ObjectSetting and DictSetting in this PR? Or in another? |
I've already deprecated them from |
Sure, please go on! |
3e4c691
to
d113db9
Compare
Done. I've also added deprecation warning to |
Perfect, let's merge it! |
I tried these custom validators and they are working great! Would it be possible to make a new release? I could use |
Great! Will do that today 🙂 |
Done 😛 |
Thank you 😉! |
Refs #35
I've tried to transform the checkers to validators. Comments are welcome.